package com.wanlian.net.core;

import com.wanlian.File.NetFileInfo;
import com.wanlian.net.File.worker.DeviceClientFileWorker;
import com.wanlian.netty.model.Address;
import com.wanlian.netty.msg.BaseMsg;
import com.wanlian.netty.msg.HoleBody;
import com.wanlian.util.DateUtil;
import com.wanlian.util.Utils;
import io.netty.channel.socket.SocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;

public class DeviceClient {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private String id;
    private String name;
    private Timestamp createTime;
    private DeviceClientWorker deviceClientWorker;
    private DeviceClientFileWorker deviceClientFileWorker;
    private String publicKey;

    /**
     * 节点hash值
     */
    private String nodeHash;
    /**
     * 节点peer通道
     */
    private ClientSocket peer;

    private Map<String, SocketChannel> peersMap;

    public DeviceClient() {
        this.createTime = DateUtil.currentTimestamp();
        this.peersMap = new HashMap<>();
        this.deviceClientWorker = new DeviceClientWorker();
        this.deviceClientFileWorker = new DeviceClientFileWorker();
        this.publicKey = Utils.getUUID();
    }

    public DeviceClient(String key) {

        this.createTime = DateUtil.currentTimestamp();
        this.peersMap = new HashMap<>();
        this.deviceClientWorker = new DeviceClientWorker();
        this.deviceClientFileWorker = new DeviceClientFileWorker();
        this.publicKey = key;
    }

    public void run() {
        // 配置sn服务器信息
        Address sAddress = new Address();
        sAddress.setIp(Constants.HOST);
        sAddress.setPort(Constants.CONNECT_PORT);
        this.peer = new ClientSocket();
        peer.setPubkey(this.getPublicKey());
        try {
            boolean bResult = this.peer.connect(sAddress);
            if (bResult) {
                this.peer.registerSnServer(this.getPublicKey());
                this.deviceClientWorker.setPeer(peer);
                this.deviceClientWorker.work();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void runFileClient() {
        Address sAddress = new Address();
        sAddress.setIp(Constants.HOST);
        sAddress.setPort(Constants.CONNECT_FILE_PORT);
        this.peer = new ClientSocket();
        peer.setPubkey(this.getPublicKey());
        try {
            boolean bResult = this.peer.connectFileWorkServer(sAddress);
            if (bResult) {
                this.deviceClientFileWorker.setPeer(peer);
                this.deviceClientFileWorker.work();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 打洞某个节点
     *
     * @param topubkey
     */
    public void HoleSomeNode(String topubkey) {
        String msg = String.format("hole someone key=%s", topubkey);
        System.out.println(msg);
        HoleBody holeBody = new HoleBody(this.getPublicKey(), topubkey);
        Address sAddress = new Address();
        sAddress.setIp(Constants.HOST);
        sAddress.setPort(Constants.HOLE_PORT);
        try {
            this.peer.holeSomeOne(sAddress, holeBody);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 先连接服务器
     *
     * @param address
     * @return
     */
    public boolean connectSnServer(Address address) {
        if (this.peer != null) {
            try {
                return this.peer.connect(address);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public void sendData(BaseMsg msg) {
        for (String peerid : peersMap.keySet()) {
            sendData(peerid, msg);
        }
    }

    private void sendData(String peerid, BaseMsg msg) {
        if (this.peer != null) {
            try {
                if (this.peersMap.containsKey(peerid)) {
                    this.peer.sendData(this.peersMap.get(peerid), msg);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 可能需要间隔一段时间更新一次
     *
     * @param peerid
     * @param channel
     */
    public void addKnowsPeer(String peerid, SocketChannel channel) {
        this.peersMap.put(peerid, channel);
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Timestamp getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Timestamp createTime) {
        this.createTime = createTime;
    }

    public String getNodeHash() {
        return nodeHash;
    }

    public void setNodeHash(String nodeHash) {
        this.nodeHash = nodeHash;
    }

    public ClientSocket getPeer() {
        return peer;
    }

    public void setPeer(ClientSocket peer) {
        this.peer = peer;
    }

    public Map<String, SocketChannel> getPeersMap() {
        return peersMap;
    }

    public void setPeersMap(Map<String, SocketChannel> peersMap) {
        this.peersMap = peersMap;
    }

    public DeviceClientWorker getEchoWorkers() {
        return deviceClientWorker;
    }

    public void setEchoWorkers(DeviceClientWorker echoWorkers) {
        this.deviceClientWorker = echoWorkers;
    }

    public String getPublicKey() {
        return publicKey;
    }

    public void setPublicKey(String publicKey) {
        this.publicKey = publicKey;
    }

    public void sendFile(NetFileInfo fileInfo) {
        deviceClientFileWorker.addToFileNeedDown(fileInfo, "aaaaaa");
    }

    public void sendDownHead(NetFileInfo fileInfo){
        this.peer.sendDownFile(fileInfo);
    }
}
